/*
 * Model.cpp
 *
 *  Created on: 28 août 2014
 *      Author: Raphaël
 */

#include <QObject>
#include <QStringList>
#include <QProcess>
#include <QtWidgets/qmessagebox.h>
#include "Model.h"
#include "raphTools/StringTokenizer.hpp"

/*** PRIVATE IMPLEMENTATION ***/
class Model::ModelPrivateImplementation : public QObject
    {
    Q_OBJECT
public:
    /*-------------------------------------------------------------------
     attributs
     -------------------------------------------------------------------*/
    Model* m_ptrModel;
    std::shared_ptr<QProcess> m_ptrLoadProcess;
    std::shared_ptr<QProcess> m_ptrSaveProcess;


    /*-------------------------------------------------------------------
     constructor/destructor
     -------------------------------------------------------------------*/
    ModelPrivateImplementation() = delete;
    ModelPrivateImplementation(Model* xPtrModel);
    virtual ~ModelPrivateImplementation();
    /*-------------------------------------------------------------------
     public methods
     -------------------------------------------------------------------*/
    void load();
    void save();

public slots:
    void onLoadProcess(int, QProcess::ExitStatus);
    void onSaveProcess(int, QProcess::ExitStatus);
    void onSaveProcessError(QProcess::ProcessError);
    };

Model::ModelPrivateImplementation::ModelPrivateImplementation(Model* xPtrModel) :
	QObject(),
	m_ptrModel(xPtrModel),
	m_ptrLoadProcess(std::make_shared<QProcess>()),
	m_ptrSaveProcess(std::make_shared<QProcess>())
    {
    connect(m_ptrLoadProcess.get(),
	    SIGNAL(finished(int, QProcess::ExitStatus)),
	    this,
    	    SLOT(onLoadProcess(int, QProcess::ExitStatus)));

    connect(m_ptrSaveProcess.get(),
	    SIGNAL(finished(int, QProcess::ExitStatus)),
	    this,
    	    SLOT(onSaveProcess(int, QProcess::ExitStatus)));

    connect(m_ptrSaveProcess.get(),
    	    SIGNAL(error(QProcess::ProcessError)),
    	    this,
    	    SLOT(onSaveProcessError(QProcess::ProcessError)));

    this->load();
    }

Model::ModelPrivateImplementation::~ModelPrivateImplementation()
    {
    m_ptrModel = nullptr;
    }

void Model::ModelPrivateImplementation::onLoadProcess(int, QProcess::ExitStatus)
    {
    m_ptrModel->m_ptrList->clear();
    auto res = m_ptrLoadProcess->readAllStandardOutput();
    ch::raph::tools::StringTokenizer stringTokenizer;
    stringTokenizer(res.cbegin(), res.cend(), ";");
    std::for_each(stringTokenizer.cbegin(), stringTokenizer.cend(), [this](const std::string &xStr)
	{
	this->m_ptrModel->m_ptrList->append(QString::fromStdString(xStr));
	});

    emit m_ptrModel->dataChanged
	(
	m_ptrModel->index(0, 0),
	m_ptrModel->index(m_ptrModel->m_ptrList->size() - 1, m_ptrModel->m_ptrList->size() - 1)
	);
    }

void Model::ModelPrivateImplementation::onSaveProcess(int, QProcess::ExitStatus)
    {

    }

void Model::ModelPrivateImplementation::onSaveProcessError(QProcess::ProcessError error)
    {
    QString msg;
    switch(error)
	{
    case 0:
	msg.append("The process failed to start. Either the invoked program is missing, or you may have insufficient permissions to invoke the program.");
	break;
    case 1:
	msg.append("The process crashed some time after starting successfully.");
	break;
    case 2:
	msg.append("The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again.");
	break;
    case 3:
	msg.append("An error occurred when attempting to read from the process. For example, the process may not be running.");
	break;
    case 4:
	msg.append("An error occurred when attempting to write to the process. For example, the process may not be running, or it may have closed its input channel.");
	break;
    case 5:
	msg.append("An unknown error occurred. This is the default return value of error().");
	break;
    default:
	break;
	}
    QMessageBox::warning(nullptr, QString("Saving"), msg, QMessageBox::Ok);
    }

void Model::ModelPrivateImplementation::load()
    {
    QString command("cmd /C echo %PATH%");
    m_ptrLoadProcess->start(command);
    }

void Model::ModelPrivateImplementation::save()
    {
    QString newPath;
    for(auto &str : *m_ptrModel->m_ptrList.get())
	{
	newPath.append(str+";");
	}

    QString command("script.bat \""+newPath+"\"");

    QProcess::startDetached(command);
    //m_ptrSaveProcess->start(command);

    }

#include "Model.moc"

/*** PUBLIC IMPLEMENTATION ***/
Model::Model(QObject *xParent) :
	QAbstractListModel(xParent),
	m_ptrList(std::make_shared<QStringList>()),
	m_ptrPrivate(std::make_shared<ModelPrivateImplementation>(this))
    {
    }

Model::~Model()
    {
    }

int Model::rowCount(const QModelIndex &) const
    {
    return m_ptrList->size();
    }
QVariant Model::data(const QModelIndex &index, int role) const
    {
    if (!index.isValid())
	{
	return QVariant();
	}
    if (index.row() >= m_ptrList->size())
	{
	return QVariant();
	}
    if (role == Qt::DisplayRole)
	{
	return m_ptrList->at(index.row());
	}
    else
	{
	return QVariant();
	}
    }
QVariant Model::headerData(int , Qt::Orientation ,int ) const
    {
    return QVariant();
    }
Qt::ItemFlags Model::flags(const QModelIndex &) const
    {
    return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
    }
bool Model::setData(const QModelIndex &index, const QVariant &value, int role)
    {
    if (index.isValid() && role == Qt::EditRole)
	{
	m_ptrList->replace(index.row(), value.toString());
	emit this->dataChanged(index, index);
	return true;
	}
    return false;
    }
bool Model::insertRows(int , int , const QModelIndex &)
    {
    return true;
    }
bool Model::removeRows(int , int , const QModelIndex &)
    {
    return true;
    }

void Model::onOkClicked(bool)
    {
    m_ptrPrivate->save();
    }

void Model::onCancelClicked(bool)
    {
    m_ptrPrivate->load();
    }
